<template>
  <n-spin class="message-container xs:h-[calc(100vh-44px)] m:h-screen" :show="mainStore.pageLoading">
    <div ref="msgContentRef" class="msg-content xs:h-[calc(100vh-148px)] m:h-[calc(100vh-104px)]">
      <div v-for="item in msgState.content" :key="item" :class="['msg-box', 'dark:border-[#20212380]',
        { 'bg-white': item.role === 'user' }, { 'bg-[#F7F7F8]': item.role === 'assistant' },
        { 'dark:bg-dark': item.role === 'user' }, { 'dark:bg-[#444654]': item.role === 'assistant' }]">
        <n-thing content-indented class="overflow-x-auto">
          <template #avatar>
            <n-avatar class="bg-[#10A37F]">
              <n-icon :component="item.role === 'user' ? PersonSharp : LogoIonitron" />
            </n-avatar>
          </template>
          <div class="cursor bg-[#374151] dark:bg-[#D1D5DB]" v-if="item.role !== 'user' && item.text === ''">
          </div>
          <div class="msg-line inline" v-if="item.role === 'user'">{{ item.text }}</div>
          <VMdPreview :text="item.text" @copy-code-success="handleCopyCodeSuccess" v-else />
        </n-thing>
      </div>
    </div>

    <ChatInput v-show="!mainStore.pageLoading" :getting="msgState.getting" @sendMsg="sendMsg"
      @changeMsg="msg => msgState.msgParams.message = msg" />
  </n-spin>
</template>

<script setup>
import { reactive, getCurrentInstance, nextTick, defineAsyncComponent } from 'vue'
import { useUserStore, useMainStore } from '@/store'
import { useRoute, onBeforeRouteUpdate } from 'vue-router'
import { messageContents, sendMessage } from '@api/chatApi'
import { LogoIonitron, PersonSharp } from '@vicons/ionicons5'
import VMdPreview from '@/utils/preview'

const ChatInput = defineAsyncComponent(() => import('./components/ChatInput.vue'))

const userStore = useUserStore()
const mainStore = useMainStore()
const { proxy } = getCurrentInstance()

const route = useRoute()

const emit = defineEmits(['openNewChat', 'addChat'])

const props = defineProps({
  message: {
    type: String
  }
})

const msgState = reactive({
  content: [],
  getting: false,
  msgParams: {
    message: '',
    parentMessageId: '', //上句消息ID，不传则不会联动上下文
    conversationId: route.params.id === 'new' ? '' : route.params.id //窗口ID，不传则为新窗口
  }
})

onBeforeRouteUpdate(route => {
  msgState.msgParams.conversationId = route.params.id
  getMsgContent(route.params.id)
})

const getMsgContent = async (id) => {
  if (id !== 'new') {
    try {
      mainStore.setPageLoading(true)
      const res = await messageContents({ conversationId: id })
      if (res.statusCode === 200) {
        msgState.content = res.data
      } else {
        emit('openNewChat')
      }
    } finally {
      mainStore.setPageLoading(false)
    }
  }
}
getMsgContent(route.params.id)

const sendMsg = async (add) => {
  if (msgState.msgParams.message && !msgState.getting) {
    msgState.getting = true
    msgState.content.length > 0 ? msgState.msgParams.parentMessageId = msgState.content[msgState.content.length - 1].id : ''
    msgState.content.push(...[
      {
        text: msgState.msgParams.message,
        role: 'user'
      },
      {
        text: '',
        role: 'assistant'
      }
    ])
    let index = msgState.content.length - 1
    try {
      const formData = { ...msgState.msgParams }
      msgState.msgParams.message = ''
      nextTick(() => {
        const msgContent = proxy.$refs?.msgContentRef
        msgContent && (msgContent.scrollTop = msgContent.scrollHeight)
      })
      const res = await sendMessage(formData)
      if (res?.statusCode === 200) {
        if (add === true && userStore.isLogin) {
          emit('addChat', { title: formData.message, conversationId: res.data.conversationId })
          msgState.msgParams.conversationId = res.data.conversationId
        }
        msgState.content[index].id = res.data.id
        msgState.content[index].text = res.data.text
      } else {
        msgState.content[index].text = res?.message || '服务器错误或请求超时，请稍后重试。'
      }
    } catch (err) {
      msgState.content[index].text = err?.message || '服务器错误或请求超时，请稍后重试。'
    } finally {
      msgState.getting = false
    }
  }
}

if (props.message) {
  msgState.msgParams.message = props.message
  sendMsg(true)
}

const handleCopyCodeSuccess = (code) => {
  $message.success('复制成功', {
    duration: 1200
  })
}
</script>

<style lang="less" scoped>
.message-container {
  width: 100%;

  &:deep(.n-spin-content) {
    display: flex;
    flex-direction: column;
    justify-content: space-between;

    .msg-content {
      width: 100%;
      overflow: auto;

      .msg-box {
        width: 100%;
        min-height: 85px;
        padding: 24px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-bottom: 1px solid #d9d9e3;

        .n-thing {
          width: 848px;
          font-size: 16px;

          .n-thing-main {
            margin-top: -5px;

            .n-thing-main__content {
              display: flex;
              align-items: center;
              height: 100%;

              .cursor {
                width: 6px;
                height: 22px;
                display: inline-block;
                animation: twinkle 1s infinite cubic-bezier(0.97, -0.4, 0, 1.32);
              }

              @keyframes twinkle {
                from {
                  opacity: 1;
                }

                to {
                  opacity: 0;
                }
              }
            }
          }
        }

        .msg-line {
          white-space: pre-line;
        }
      }
    }
  }

  .n-input {
    margin: 0 auto;
  }
}
</style>